//----------------------------------------------------------------------------
//  ,-.
// /_\___ ,   Ninja Framework
// '  ___\    (C) Riccardo Capra - http://riccar.do
//  //   \\
//----------------------------------------------------------------------------
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------

#ifndef NJ_DUMMY_SYNC_OBJECT_H
#	define NJ_DUMMY_SYNC_OBJECT_H

#	include "NjNinjaSyncLib.h"
#	include "NjLocker.h"
#	include "NjAtomic.h"
#	include "NjEventsSystem.h"
#	include "NjDummySyncObject_config.h"

	/// \brief Implements a dummy synchronization object
	///
	/// This class has the same interface of NjRecursiveMutex but Lock calls are not really blocking.
	/// On debug build configurations it ensures (through an assertion) that two threads do not try concurrently to lock the same resource
	class NjDummySyncObject
	{
	public:
		/// \brief Defines a scoped-lock for NjDummySynchObject
		typedef NjLocker<NjDummySyncObject> Locker;

		/// \brief Defines the timeout type
		typedef NjEventsSystem::TimeMs TimeMs;

		/// \brief Creates a NjDummySyncObject instance
		NjDummySyncObject();

		/// \brief Destroys this NjDummySyncObject instance
		~NjDummySyncObject();

		/// \brief Acquires the synchronization object and put it in locked state
		///
		/// If other threads will try to acquire the lock, on some build configurations an assertion will be triggered, otherwise nothing will happen and the thread will be not blocked.
		/// The calling thread can then release the synchronization object with an Unlock call
		void Lock();

		/// \brief Behaves exactly as Lock
		/// \param uTimeMs is ignored. The function will always immediately return 
		/// \return Always NJ_TRUE
		NjBool TryLock(TimeMs uTimeMs);

		/// \brief Releases a previously acquired synchronization object. Just the thread that initially successfully acquired the synchronization object can call Unlock.
		/// This condition is enforced in some build configurations through assertions.
		/// To fully release a synchronization object the locking thread should call Unlock exactly the same amount of times it previously called Lock
		void Unlock();

	private:
#	if NJ_DUMMY_SYNC_OBJECT_TRACKING_ENABLED || NJ_DUMMY_SYNC_OBJECT_STORE_LOCKER_ENABLED
		/// \brief Not inlined constructor implementation
		void DebugInitialize();

		/// \brief Not inlined destructor implementation
		void DebugUninitialize();

		/// \brief Not inlined Lock implementation
		void DebugLock();

		/// \brief Not inlined Unlock implementation
		void DebugUnlock();

#		if NJ_DUMMY_SYNC_OBJECT_TRACKING_ENABLED
		/// \brief Class to track dummy synchronization objects usage
		class TrackerEntry;

		/// \copydoc TrackerEntry
		class Tracker;
#		endif // NJ_DUMMY_SYNC_OBJECT_TRACKING_ENABLED

#		if NJ_DUMMY_SYNC_OBJECT_STORE_LOCKER_ENABLED
		/// \brief Stores the current thread locking the resource
		NjAtomic<NjUint> m_kThreadDebugId;

		/// \brief Recursion counter
		NjUint m_uDebugCounter;
#		endif // NJ_DUMMY_SYNC_OBJECT_STORE_LOCKER_ENABLED
#	endif // NJ_DUMMY_SYNC_OBJECT_TRACKING_ENABLED || NJ_DUMMY_SYNC_OBJECT_STORE_LOCKER_ENABLED

		NJ_DISABLE_COPY(NjDummySyncObject);
	};

#	include "NjDummySyncObject_inline.h"

#endif // NJ_DUMMY_SYNC_OBJECT_H
